home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
batchut
/
rap101.zip
/
COMMON.MAN
< prev
next >
Wrap
Text File
|
1992-05-08
|
105KB
|
3,076 lines
A Common Subroutine Library
for RAP Programmers
by Kirk H. Parker and Gary F. Simons
Occasional Publications in Academic Computing
Number 10
Summer Institute of Linguistics
Dallas, Texas
This book is sold with the software it describes. That software,
too, is the copyrighted property of the Summer Institute of
Linguistics. However, in the interest of sharing the fruit of
our research with the larger academic community, the registered
owner of the RAP software is granted the right to share copies of
the distribution diskette with friends and associates, provided
this is not done for commercial gain. Such recipients of the
software, if they decide to use it in their research, should in
turn become registered owners by buying this book with its latest
version of the software.
Copyright 1988 by the Summer Institute of Linguistics
All rights reserved
CONTENTS
1. Introduction 5
1.1 Getting answers from the user 6
1.2 File handling 7
1.3 Help system 8
1.4 String processing 9
1.5 Terminal control 9
2. Using the common subroutine library 11
2.1 Global variables used by the library 12
2.2 Defined constants used by the library 13
2.3 Internal error messages 14
2.4 Including the library in your programs 15
3. The help system 17
3.1 Creating a help file 18
3.1.1 Source file format markers 19
3.1.2 Producing the working help file 20
3.2 Using the help file in your program 21
3.2.1 Opening the help file 22
3.2.2 Using explain and #verbose 22
3.2.3 Using the $topic parameter 23
3.2.4 Help in menus 24
4. An example program 27
4.1 File header and .include files 28
4.2 Defined constants 29
4.3 Main subroutine 29
4.4 Testing the environment 31
4.5 Getting the parameters 33
4.6 Generating a customized PTP program 34
4.7 Running the generated PTP program 38
5. Reference summary of the COMMON subroutine library 41
References 97
Index 99
----------------------------------------------------------------
Chapter 1
INTRODUCTION
1.1 Getting answers from the user
1.2 File handling
1.3 Help system
1.4 String processing
1.5 Terminal control
The RAP language (Strangfeld 1988) was designed especially for
writing computer programs that interact heavily with users. RAP
makes it easy to display text on the terminal screen, and to get
and test responses typed by users. RAP's high-level features,
such as the menu-construct and built-in pattern matching, allow
complicated control structures to be programmed with a minimum of
effort.
The philosophy behind RAP is not, however, to provide every
possible user-interface feature as a built-in function. Instead,
RAP seeks to provide the basic building blocks from which such
features can be constructed. To support this, RAP provides for
extension in two ways: the set of program commands can be
extended by adding user-defined procedures, and the set of
program functions can be extended by adding user-defined numeric
functions and string functions. These user-defined constructs we
refer to collectively as subroutines, or simply routines.
This volume describes one set of subroutines which extend RAP's
capabilities in the areas of user interaction, file handling,
context-sensitive help, string processing, and terminal control.
The subroutine library is called COMMON, because it contains a
set of commonly needed procedures and functions. We envision
that this COMMON library will be used by virtually every RAP
application program. The library is contained in the file
COMMON.RAP. To make use of the subroutines, a programmer needs
only to include the line
.include common.rap
in the main RAP program file. The simplicity of accessing the
library makes it possible for even novice programmers to make
full use of the subroutines.
The following sections give a brief overview of the library,
listing the subroutines according to general functional
categories.
1.1 Getting answers from the user
The COMMON library includes routines to get and validate user
inputs. All of these routines allow the programmer to specify a
prompt and a default response. Programmers can specify limits
such as string length, minimum and maximum numeric values, and so
on. The routines in this group, listed below, also allow the
programmer to specify a help topic as a parameter. If a help
topic is provided, the user can display the help information by
entering ? or help in response to the prompt.
*get_code Get an SIL standard format marker (slash code)
from the user.
*get_num Get a number from the user.
*get_str Get a string from the user.
*get_ans Display a query and get a response from the
user≡a low-level function used by the other
functions in this group.
*no Ask the user a yes/no question, reporting true if
the answer is no.
*yes Ask the user a yes/no question, reporting true if
the answer is yes.
1.2 File handling
The COMMON library includes subroutines which get file names
and then verify that they can be used safely for input or output.
Other subroutines support safe deletion of files, automatic
generation of backup files, and control of mounted disk files or
volumes.
*delq Interactively delete a file and report the
result. If the file exists, the user is asked
whether or not to delete it.
*get_append_file Get a file name for editing or updating.
Create an empty file if none exists, but preserve
the contents of an existing file.
*get_fixed_output Ensure that a predefined name can be used for
an output file. Optionally get a substitute name
from the user, if not.
*get_input_file Get a file name from the user and ensure that
it is a valid, existing file.
*get_output_file Get a file name from the user for an output
file. If a file with the given name already
exists, the user is asked whether or not to
overwrite it.
make_bak_file Perform an automatic file backup. The existing
.BAK file is deleted, the previous version of the
file is renamed as a .BAK file, and the .TMP file
is renamed to the original name.
make_bak_to_bat Perform an automatic file backup as above,
but do so by writing the necessary DOS commands
to a batch file. This is required when the
target machine does not have enough memory for
RAP to execute DOS-level commands as subtasks.
*make_tmp_output Generate and validate a temporary output file
name.
mount_file Ensure that a particular data file is mounted.
mount_program Ensure that a particular program file is mounted.
mount_volume Ensure that a particular disk volume is mounted
in a particular drive.
Also included are some lower-level subroutines used to build the
above file-handling routines. They can be used to build
specialized file-handling routines.
*deletef Delete a file and report the result.
*ensure_dot Ensure that a file extension begins with a dot.
ensure_space Test for disk space for output file. If there is
not enough room, ask the user to delete some
files.
*get_filespec Get a filespec from the user and ensure that it
is well-formed.
*parse_filespec Ensure that a filespec is well-formed, and
break it down to its four main components.
*val_dir Report if the subdirectory part of a path name is
valid.
*val_drive Report if a drive name is valid.
*val_ext Report if a file extension is valid.
1.3 Help system
The COMMON library includes routines to support on-line help.
The help information is stored as text in a file external to the
application program. Help specific to the current context in the
program is displayed, either when the program explicitly commands
it, or when the user asks for help by typing ? or help in
response to one of the query routines of the library.
explain Display help information on a given topic.
open_help Open the program's help file.
1.4 String processing
The COMMON library extends RAP's built-in string operations
with a few higher-level routines.
*to_lower Convert all upper-case letters in a string to
lower-case.
*to_upper Convert all lower-case letters in a string to
upper-case.
*trim Remove leading and trailing spaces and tabs from
a string.
1.5 Terminal control
The COMMON library provides routines which give the programmer
control over the terminal in case something goes wrong. For the
screen this involves the display of error and warning messages
with built-in pause to ensure that the user sees them. For the
keyboard this involves flushing the type-ahead buffer to remove
input that is potentially invalidated by the occurrence of a
problem.
kbflush Remove any keystrokes in the type-ahead buffer.
message Display a message text and pause to ensure the
user sees it.
retry Display an error message resulting from invalid
user input, and ask the user to re-enter the
answer.
----------------------------------------------------------------
Chapter 2
USING THE COMMON SUBROUTINE LIBRARY
2.1 Global variables used by the library
2.2 Defined constants used by the library
2.3 Internal error messages
2.4 Including the library in your programs
There are a number of things you must know in order to use
COMMON.RAP correctly in your own program. First, you must know
what subroutines are in the library and how each is used. An
overview is given in chapter 1; full details are provided in
chapter 5. If you want to provide users with context-sensitive
help, you will need to understand how the subroutine library's
help system works; this is explained in chapter 3. The current
chapter covers topics which are relevant to the subroutine
library in general, namely, the global variables and defined
constants used in the library, the internal error mechanism, and
how to include the COMMON.RAP file in your program. Chapter 4
ties everything together with a complete sample program.
2.1 Global variables used by the library
The subroutine library creates and uses a number of global
variables. Some of them are primarily for internal use by the
subroutines. Others are directly useful to the programmer. In
either case, programmers must avoid using these names for their
own variables. These global variables are:
$drive The drive part of the most recent filespec
entered by the user.
$ext The extension part of the most recent filespec
entered by the user.
#filesize The size (in kilobytes) of the last input file
entered by user. (Note that RAP's built-in
functions *filesize, *freesp, and *memfree work
in units of bytes, rather than kilobytes. The
programmer who wants to mix COMMON's high-level
routines with direct calls to RAP's built-in
functions must be sure to compensate.)
$name The name part of the most recent filespec entered
by the user.
$skip Used by the subroutines to adapt to different
display sizes. This variable contains a null
string if the program is running on a Sharp PC-
5000, and a newline character on other machines.
$skip allows subroutines to include blank lines
where desired on PC-compatibles, without wasting
screen lines on the Sharp. Your own subroutines
can make use of this variable.
$subdir The subdirectory part of the most recent filespec
entered by the user.
$valdr Contains a list of valid disk drive designators
for the machine on which the program is running.
See the entry in chapter 5 for the subroutine
*val_drive for more information on this variable.
#verbose Enables or disables the help function provided by
the subroutine explain.
In addition to these variables, COMMON uses a few which are for
internal use only. The names of these variables all end with two
underscores. Your programs should avoid using any names that end
with two underscores to avoid possible conflicts with these
names.
2.2 Defined constants used by the library
COMMON.RAP includes a number of defined constants. Like the
global variables, some of them may be directly useful to the
programmer and all of them are reserved names (that is, they
cannot be used by a programmer to define some other value).
The .define's are used because they make programs easier to
read, write, and understand. For example, instead of writing
if (*existf($some_file) == 4)
t:Sorry, you can't delete that file.
you can write
if (*existf($some_file) == .READONLY)
t:Sorry, you can't delete that file.
Not only is the latter clearer to someone else reading the
program, it is also easier for the programmer to write; most
people can remember .READONLY more readily than they can remember
that 4 means a read-only file!
The defined symbols fall into three categories. The first
consists of return values for the library subroutines themselves:
.YES 1
.NO 0
The second group represents return values from the built-in
function *existf:
.NOTFOUND 0
.READWRITE 2
.READONLY 4
The third group contains general system values and useful
abbreviations:
.MININT The smallest negative number allowed by RAP.
.MAXINT The largest positive number allowed by RAP.
.FILECHARS A list of all characters which are valid in file
names, namely, all upper- and lower-case letters,
all digits, and the following punctuation marks:
!@#$%^&()'`{}~-_
.MAXCODE The maximum length allowed for a standard format
marker.
.LOCALMATCH Contains the string "declare $left, $match,
$right". When executed in a RAP program, this
code creates local copies of the pattern-matching
variables. This definition serves two purposes:
the defined name is shorter (and easier to type)
than its replacement, and it more clearly
documents the reason for the declared variables.
2.3 Internal error messages
It is possible to call a subroutine with invalid parameters.
For example, the library subroutine *get_num, which gets a number
from the user, allows the programmer to specify limits for the
minimum and maximum values the user is allowed to enter. What
happens if the programmer accidentally sets the maximum limit
less than the minimum? If the subroutine did nothing about this
error, the user would be unable to enter a valid response.
The library subroutines attempt to detect such invalid
parameters, because invalid parameters represent serious logical
errors in the program, and may well cause the program to give
invalid results. If such an error is detected, an internal error
message similar to the following is displayed:
Internal error in *get_num:
minimum greater than maximum
The program will continue to run, but the results
may not be correct. Copy this message for reporting
to the program's author. You may quit immediately
by typing Ctrl-C.
This warns the user that something has gone wrong in the program
and supplies debugging information that can be passed on to the
programmer. Of course, if you are careful about testing your
programs before releasing them, you will encounter all the
internal error messages yourself and correct the errors before
releasing your program. If you do this, the end user should
never see such a message.
2.4 Including the library in your programs
To use the subroutines in the library, you must use the
.include command to bring the file COMMON.RAP into your program.
Except for any loose code you may have at the beginning of your
program file, .include COMMON.RAP must be the first command in
the file. This is necessary because COMMON.RAP begins with loose
code which initializes key variables like #verbose and $skip. If
you fail to put .include COMMON.RAP in the right place, the loose
code will cause program loading to terminate with the message,
"Unreachable statement(s) found after proc/function end."
After .include COMMON.RAP, we recommend that you put your
.define's, then your .include's, then your main procedure, and
finally all other procedure and function definitions. This
arrangement of a RAP program is illustrated in the following
example:
; sample.rap sample program showing how to
; include COMMON.RAP
;----------------------------------------------------------
; We do not recommend that you use loose code in your
; programs, but if you do, ALL loose code must come here
; before including COMMON.RAP.
.include common.rap
;----------------------------------------------------------
; Any .defines that you want to be available to your whole
; program should come next -- for example, a default record
; marker:
.define .DEFAULT_MARK last_name
;----------------------------------------------------------
; Next comes any other include-files. For example, you may
; have a file of RAP subroutines that generate Manuscripter
; commands:
.include ms_gen.rap
;----------------------------------------------------------
; As a matter of style, the main procedure should be the
; first subroutine in your program.
proc main()
; If you are supplying a help file with your program, you
; must open it by calling open_help before calling any
; other library subroutine
cls
t: SAMPLE.RAP
open_help("my_help.hlp")
...
end proc
;----------------------------------------------------------
; After the main procedure come any other subroutines
; in your program file:
proc page_params() ; get Manuscripter page parameters
...
end proc
...
----------------------------------------------------------------
Chapter 3
THE HELP SYSTEM
3.1 Creating a help file
3.1.1 Source file format markers
3.1.2 Producing the working help file
3.2 Using the help file in your program
3.2.1 Opening the help file
3.2.2 Using explain and #verbose
3.2.3 Using the $topic parameter
3.2.4 Help in menus
It is important for your programs to provide on-line help.
Although a printed manual is a key part of a program package,
users who have questions while running a program ideally should
not have to search through the manual. The COMMON library
provides an extensive help system that allows you to provide
context-sensitive help information for your users.
The library supports two ways of displaying help information.
The first is using the subroutine explain. For example, in order
to present an introduction to the user, you could write the
following command into your program:
explain("intro")
The second means is provided by the interactive input routines:
*get_ans, *get_append_file, *get_code, *get_filespec,
*get_fixed_output, *get_input_file, *get_num, *get_output_file,
*get_str, *no, and *yes. These functions all have a parameter
called $topic. When you pass the name of a help topic to one of
these routines, the help information is displayed if the user
types ? or help in response to the query. This means that every
time you ask users for input, you can provide explanatory help
for that specific input.
The help system uses an external help file rather than
including the help text in the program file. An external file
has two benefits. The first is that the help file and the
program can be revised independently of each other. The second
is that the help file does not take up any memory space while the
program is running. There is thus no penalty for including
extensive on-line help messages.
3.1 Creating a help file
Creating a help file involves two steps. The first is to write
a text file containing the help text for every topic. This is
called the source file. The second is to process that file with
the helpgen program. (This program is included on the RAP
release disk as HELPGEN.EXE.) Helpgen reads the source file and
generates an index for it which enables explain to quickly find
the help text associated with any given help topic. Helpgen then
writes a new copy of the help texts with the index added at the
beginning. This indexed file is called the help file.
You should not attempt to edit the help file created by
helpgen. The index uses a byte count to indicate the starting
location of each topic entry. If your attempted revision changes
the length of the file by even one byte, all or part of the help
file will be rendered invalid. An incorrectly indexed help file
can even cause RAP to abort the current program and return to the
command level! The only safe way to change a help file is to
edit the source file and process it again with helpgen.
3.1.1 Source file format markers
The source file is a plain ASCII text file which uses SIL
standard format markers to organize it. SIL standard format is a
convention which prescribes that different types of information
in text files should be marked by unique codes beginning with the
backslash character. (For this reason, standard format markers
are also called slash codes.) The following standard format
markers are recognized in the help source file:
\id File identification. The first line of the file, if so
marked, contains identification information inserted by
the author of the source file. It is optional, but
strongly recommended!
\topic Help topic definition. This marker must be followed by
the name of a help topic on the same line. Topic names
follow the same rules as RAP names: they must begin
with a letter, contain only letters, numbers, and
underscores, and be no longer than 19 characters. Upper
and lower case are considered equal: INTRO, Intro, and
intro all refer to the same help topic.
\cls Performs a RAP cls (clear screen and home cursor)
command when encountered in a help text being
displayed. This marker must be alone on a line.
\foot Performs a RAP foot (pause at foot of screen) command
when encountered in a help text being displayed. This
marker must be alone on a line.
\__ Reserved for use by helpgen (backslash followed by two
underscores).
In order to be recognized, these markers must begin at the left
margin. Any lines beginning with anything else (including other
standard format markers) are part of the help text for the topic
defined by the most recent \topic.
The \foot and \cls markers are never required, provided RAP's
automatic screen paging is enabled. If you have turned off the
paging by the RAP statement #paged = 0, you will probably need to
use \foot in your help texts to prevent help information from
scrolling off the screen before it can be read. Even if paging
is on, you may want to use these markers to group your help text
into paragraphs or "screenfuls." Another use for \cls is to
clear the screen before beginning the help text. In this case,
the \cls should be on the first line after the \topic.
You may use any printing characters in the help source file,
including extended ASCII characters. You should not include any
control characters (not even TABs). Blank lines in the source
text are not modified in any way, so you may use them to format
your help text into paragraphs.
The following is a sample help source file which defines help
texts for three topics, namely intro, help_source, and help_file:
\id sample.txt Sample help file source 14-DEC-87 khp
\topic intro
Welcome to the sample program. This is only a sample.
If it had been a real program, some useful data would
have been produced or processed.
\topic help_source
A help source file is a standard format file containing
the help text.
\topic help_file
The actual help file contains an index to the help
topics, followed by the contents of the source file.
\foot
The help file is created from the source file by the
program HELPGEN.EXE. This program generates an index to
the help topics, and then creates the help file which
contains the index followed by all of the help texts.
\foot
\cls
Note that if you use \cls on any line except the first line of a
topic, you should place a \foot before it to prevent the screen
from clearing before the user has read the help text.
3.1.2 Producing the working help file
After creating the help source file, you process it with the
program helpgen. This creates the working help file that you use
with your RAP program. Helpgen takes two command-line parameters,
the name of the input source file and the name of the desired
output help file. Helpgen prompts you for any parameters you
don't enter on the command line. Thus you may run helpgen with
one of the following command lines:
helpgen
helpgen input_file
helpgen input_file output_file
If you don't specify an output file name, it will suggest a
default name based on the input file name with the extension
.HLP. Regardless of how the file names are obtained, helpgen
prevents you from entering the same name for both input and
output.
As helpgen runs, it may display error messages like the
following:
Error in line number: \topic without argument
Error in line number: duplicate name (topic_name)
Error in line number: file too big (\topic topic_name)
The first message means that you forgot to include a topic name
after the \topic marker, or that the name is on the following
line instead of the same line. Edit the source file and add or
move the name as required, and run helpgen again.
The second message means that you have used the same name for
more than one \topic entry. If you attempted to use the help
file, *explain would only be able to find the first entry. Edit
the help source file and change one of the names. Then run
helpgen again. You may also need to edit your RAP source files
and revise the topic names used there.
The final error message indicates a more serious problem with
your help file. Help files have an absolute upper size limit.
(The limit may vary with versions of helpgen. See the README
file on the release disk for the exact limit of the version you
have.) The error message means that, after processing, the size
limit has been reached before all the text for the named topic
was included. You must reduce the overall size of the help
source file.
3.2 Using the help file in your program
After you have created a help file, you can use it in your
program. You need to open the help file, use the explain
procedure and the $topic parameters, and optionally set or reset
the global variable #verbose.
3.2.1 Opening the help file
The first step in using the help file is to call the subroutine
open_help to open the file. You should do this early in your
main procedure, and must do it before any calls to any other
library subroutines. Here is a simple example:
; helpdemo.rap demonstrate use of open_help in a
; program to help user generate a
; help source file
.include common.rap
proc main
open_help("helptest.hlp")
; now we can use explain:
explain("intro")
; as well as calls to the library that include
; $topic parameters:
if (*yes("Do you want to produce a help source file","",+
"help_source"))
produce_source
end if
end proc
3.2.2 Using explain and #verbose
The subroutine explain is used to display help information when
the programmer wants to force an explanation, rather than waiting
for the user to ask for help when answering a query. In the
example above, explain("intro") will always display an
introduction at the beginning of the program.
The example has one obvious problem, however. As users become
familiar with the program, they will probably get tired of seeing
the introduction every time they run it. A good help system
should display information only when it is needed and wanted.
One solution would be to write
if (*yes("Do you want to read the introduction","",""))
explain("intro")
end if
But if the program contains numerous calls to explain, every one
will have to be enclosed within an if-construct. To avoid this
necessity, explain checks the value of the global variable
#verbose every time it is called. If #verbose has a value of
zero, explain returns immediately to the calling routine without
displaying anything. If the value is non-zero, the explanation
is given as normal. You can thus enable or disable explanations
for the entire program by setting the value of #verbose. For
instance, a program could be written like this in order to allow
the user to control the display the explanations:
.include common.rap
proc main
open_help("helptest.hlp")
#verbose = *yes("Do you want instructions","","")
explain("intro")
...
explain("helpgen")
...
end proc
Not only does #verbose make it easier for the programmer to write
the program, it also makes it more convenient for the experienced
user who can turn off all the explanations by answering a single
question.
3.2.3 Using the $topic parameter
When one of the interactive input subroutines is used, the
programmer can provide a help topic. The help topic will be
displayed if the user enters ? or help in response to the query.
For instance, in the previous example we could rewrite the line
which sets #verbose to include a help topic for *yes:
#verbose = *yes("Do you want instructions","","verbose")
In this case, the help topic verbose would explain something
about the instructions available in the program and about the
consequences of answering yes or no to the query. Ideally, any
time the user is asked for input, the program should provide a
help topic to give a brief explanation of the significance of the
answer, of the range of allowable answers, and so forth.
The explanations provided for help topics passed as $topic
parameters are not affected by the setting of #verbose. #Verbose
only affects calls to explain that are part of your RAP program.
This means that users can turn off informative or tutorial
explanations without losing the ability to call for help when
needed.
This effect is achieved by declaring a local copy of #verbose
within the lowest-level subroutine which COMMON.RAP uses for user
input. The essential structure of this subroutine, called
*get_ans, is sketched below:
string func *get_ans( . . , $topic, . .)
declare #verbose ; create a local version of #verbose
#verbose = 1 ; explain is now enabled, but the
; previous setting will be restored
; when this function returns.
...
if ($answer == "?" or $answer == "help")
explain($topic)
end if
...
end func
You may find this method of declaring local variables, whether to
override or to protect the values of higher level variables, to
be useful within your own programs.
3.2.4 Help in menus
RAP's menu-construct has a built-in help mechanism. The code
following the help statement is executed if the user responds to
the query with ? or help. You can integrate this with the help
topic system of COMMON by calling explain from the help section
of a menu-construct. You may want to declare a local copy of
#verbose so the explanation is not affected by if the global
version is set to zero. For instance,
proc do_glossing
declare #verbose
#verbose = 1
loop
menu: IT glossing menu
option:Prepare a text for glossing
do_itprep
option:Gloss a text
do_itp
option:Return to main menu
return
help:
explain("glossing_options")
end menu
end loop
end proc
----------------------------------------------------------------
Chapter 5
REFERENCE SUMMARY OF THE COMMON SUBROUTINE LIBRARY
This chapter defines each subroutine in the COMMON library in
full detail. The subroutines are listed alphabetically. Each
entry begins a new page. Entries are headed by the name of the
subroutine, followed by a parenthesized list of parameters. If
the subroutine is a function, its name is preceded by an asterisk
(*). The parameter names are preceded by $ or #, depending on
whether they are string or numeric values. Consequently, the
entry header looks like a call to the subroutine would look in a
RAP program. The entries are organized under the following
subheadings:
Description
A description of the subroutine's function.
Parameters
A list of all the parameters with a brief description of each.
Return value
A description of the subroutine's return value. None indicates
that the subroutine is a procedure. String and numeric
functions are distinguished by wording which states whether the
return value is a string or a number.
Global variables used
A description of any global variables used or modified by the
subroutine.
Remarks
Any further information needed to properly use the subroutine.
User error handling
A description of how the subroutine handles invalid user input,
including an explanation of any messages generated by the
subroutine.
Parameter validation
A description of any checking the subroutine does for invalid
parameter values. If there is a particular kind of invalid
parameter which is not tested for, that is mentioned as well.
Example
A brief example of using the subroutine.
_________________________________________________________________
*deletef($filespec)
_________________________________________________________________
Description
Deletes $filespec if possible, and reports the result by means
of a return value. The file is deleted without informing the
user or asking for confirmation.
Parameters
$filespec the file to be deleted
Return value
A number which is .READWRITE if the file was successfully
deleted, .NOTFOUND if it did not exist, or .READONLY if the
file exists and is read-only and thus cannot be deleted.
Remarks
*Deletef is not interactive; no messages are displayed.
Application programs should always use this function instead of
using killf directly. The problem with using killf is that if
the file is read-only or non-existent, the RAP program is
aborted and the user is returned to the RAP immediate mode.
A return value of .READWRITE or .NOTFOUND means that the named
file no longer exists. You can now use that name for creating
a new file. A return value of .READONLY means that the file
could not be deleted. If you were to try using the RAP *open
function to create a new file with that name, the RAP program
would be aborted and the user would be returned to the RAP
immediate mode prompt.
Example
; ensure that the external program can write $outfile
if (*deletef($outfile) == .READONLY)
t:*chr(7)\
t:We need to delete $outfile, but you've made it
t:read-only. Please rename the file, or delete it,
t:and then re-run this program.
foot
bye
else
xs $program $infile $outfile
end if
_________________________________________________________________
*delq($filespec)
_________________________________________________________________
Description
If $filespec exists, query user before deleting it.
Parameters
$filespec the file to be deleted
Return value
A number which is .READWRITE if the file was successfully
deleted, .NOTFOUND if no file existed, or .READONLY if the file
is read-only or the user said not to delete it.
Remarks
*Delq is interactive. It is like *deletef but differs in that
it asks the user's permission before deleting the file, rather
than doing so silently. It also displays an error message if
the file is read-only.
A return value of .READWRITE or .NOTFOUND means that the named
file no longer exists. You can now use that name for creating
a new file. A return value of .READONLY means that the user
did not want to delete the file, or else that it could not be
deleted.
Example
; repeat until we get a valid output file
loop
$outfile=*get_filespec("Output file","","","","")
until (*delq($outfile) <> .READONLY)
_________________________________________________________________
*ensure_dot($ext)
_________________________________________________________________
Description
Ensures that a non-null file name extension begins with a dot.
If the proposed extension is the null string, then no dot is
added.
Parameters
$ext the extension to be regularized
Return value
A string which is an extension guaranteed to begin with a dot,
or to be the null string.
Remarks
*Ensure_dot does not test the extension for validity. Use
*val_ext for that purpose.
Example
$newext=*get_str("New extension",".TXT","extensions",0,4)
$newext=*ensure_dot($newext)
_________________________________________________________________
ensure_space($drive,$subdir,#space)
_________________________________________________________________
Description
Ensures that there is enough space for an output file.
Parameters
$drive the drive where the file will be written
$subdir the directory where the file will be written
#space the needed free space in kilobytes
Return value
None.
Remarks
If there are not at least #space kilobytes of free space on the
named drive, the user is prompted to delete some files on the
disk. The user can request to see a display of the current
directory by typing dir. The directory shown is the
subdirectory passed as the $subdir parameter. A different
directory, or a subset of the files in a directory, can be
displayed by typing dir followed by a filespec. The normal DOS
wildcard characters (* and ?) are valid in these filespecs.
The drive is not changed from the drive specified in the
$drive parameter, even if the user references a different drive
in a filespec. The subroutine is trying to ensure that there
is space on the specified drive≡it would do no good to delete
files from a different drive. Instead, a warning message is
displayed and no files are deleted.
The #size parameter is expressed in terms of kilobytes. Note
that RAP's built-in functions *filesize, *freesp, and *memfree
work in units of bytes, rather than kilobytes. The programmer
who wants to mix COMMON's high-level routines with direct calls
to RAP's built-in functions must be sure to compensate. To
convert from kilobytes to bytes, multiply by 1024. To round up
from bytes to the nearest kilobyte, add 1023 and divide by
1024.
There are some potential dangers in using this routine. For
example, it is possible for the user to delete a file which has
already been validated as existing by *get_input_file or
*get_append_file. The user may not have any unnecessary files
on that disk. Or, the user may try to change disks when it is
not safe to do so (see mount_volume for a discussion of this).
If the user cannot make enough room, his only recourse is to
abort the RAP program by typing Ctrl-C, losing any data that
has not been written to a file. It is therefore recommended
that this procedure not be called when a file is open or when
information collected by the RAP program has not yet been
written out.
User error handling
If the user enters a drive designator as part of the filespec
to delete, a warning message is displayed, and no files are
deleted. The user is then prompted to re-enter a valid
filespec which contains no drive designation.
Example
; make sure there is 100K of free space on drive C:
ensure_space("C:","",100)
_________________________________________________________________
explain($topic)
_________________________________________________________________
Description
Displays help information for the given topic.
Parameters
$topic the topic about which help is desired
Return value
None.
Global variables used
#verbose enables explanations if non-zero
Remarks
See chapter 3 for details on how to create a help file and use
explain in your programs.
In order for explain to function at all, you must have
previously opened the help file using the subroutine open_help.
Parameter validation
If the help file is not open, the message "Sorry, there is no
help file available to this program" is displayed.
If the topic is not found in the help-file index, the message
"Sorry, there is no help for this topic" is displayed. Neither
of these messages are treated as internal error messages (that
is, they do not advise the user to exit as soon as possible).
An invalid help-topic is primarily an annoyance to the user,
not an indication that the program is likely to produce invalid
results.
Example
if (*yes("Do you want an introduction to IT","n",""))
explain("intro")
end if
_________________________________________________________________
*get_ans($query,$default,$topic,#oblig)
_________________________________________________________________
Description
Asks a question, displaying a default response if any, and
returns the user's response. Displays help information on the
given topic if user enters ? or help.
Parameters
$query the question to ask
$default the default response ("", if none)
$topic the help topic ("", if none)
#oblig .YES if answer is required; .NO if null response
allowed.
Return value
A string which is the user's response to the query. If a
$default parameter is supplied, that string is returned if the
user simply hits Enter.
Remarks
If the $query parameter does not end with a question mark or
colon, *get_ans automatically appends a question mark. If a
non-null value is specified for $default, its value enclosed
within square brackets is added to the displayed query.
*Get_ans should not be used to get string responses from the
user≡use *get_str for that purpose. *Get_ans is intended to be
used as a building block for subroutines similar to *get_str.
(See example below.)
User error handling
If #oblig is .YES and no $default parameter is supplied, the
user is forced to enter a nonblank answer. If the user only
hits Enter when it is not allowed, the message "This question
requires an answer" is displayed, and then the original query
is redisplayed.
If the user enters ? or help when no $topic parameter is
provided, the message "There is no help for this question" is
displayed, and the query is redisplayed.
Example
; get a list of punctuation marks from the user.
string func get_punctuation($query,$default,$topic)
declare $answer
loop
$answer=get_ans($query,$default,$topic,.YES)
if ($answer has "[ \\tA-Z1-9]"))
error("Please enter punctuation characters only",+
$topic)
else
return $answer
end if
end loop
end func
_________________________________________________________________
*get_append_file($query,$defpath,$defname,$defext,$topic)
_________________________________________________________________
Description
Gets the name of a file for editing or updating. If the
requested file does not exist, *get_append_file creates it.
Requires user to select another file or to rename the requested
file if it has a .TMP or .BAK extension. If the user enters
dir, or dir followed by a filespec, the directory is displayed
and the query is redisplayed.
Parameters
$query the question to ask
$defpath default drive and subdirectory path
$defname default file name (without extension)
$defext default file extension
$topic the help topic ("", if no help)
Return value
A string which is the filespec of a suitable file.
Global variables used
#filesize the size of the file in kilobytes
$drive the drive part of the returned filespec
$subdir the subdirectory part of the returned filespec
$name the name part of the returned filespec
$ext the extension part of the returned filespec
Remarks
*Get_append_file does not open the file. Its purpose is to get
a filespec which may be used with *open or with an external
program using xs or xcall.
This subroutine is similar to *get_input_file, except that the
requested file does not need to exist. It is appropriate for
filespecs that will be used with text editors and similar
applications. The file on which an editor is invoked is not an
input file, because if the file does not exist it will be
created, and if the file already exists it gets written to as
well as read from. On the other hand, you cannot use
*get_output_file to get such a filespec, because that
subroutine deletes the requested file if it already exists.
*Get_append_file creates an empty file if the requested file
does not exist.
See the remarks under *get_filespec for the constraints on
values of the default filespec parameters ($defpath, $defname,
and $defext), and for an explanation of exactly what is
returned in the four global filespec variables ($drive,
$subdir, $name, and $ext).
The file size returned in #filesize is rounded up to the
nearest kilobyte. Note that RAP's built-in functions
*filesize, *freesp, and *memfree work in units of bytes, rather
than kilobytes. The programmer who wants to mix COMMON's high-
level routines with direct calls to RAP's built-in functions
must be sure to compensate. To convert from kilobytes to
bytes, multiply by 1024. To round up from bytes to the nearest
kilobyte, add 1023 and divide by 1024.
User error handling
The requested file cannot be read-only. If it is, a message is
displayed and the user is allowed to enter another filespec.
The requested file cannot have the extension .TMP or .BAK. If
it does, a message is displayed and the user is allowed to
rename the file to a different extension or to enter a new
filespec.
Example
; use text editor to enter free-form text
$file=*get_append_file("File to edit","","","","")
xs ed $file
_________________________________________________________________
*get_code($query,$default,$topic,#minlen,#maxlen)
_________________________________________________________________
Description
Gets a slash code (standard format marker) from the user. The
return value does not contain the backslash.
Parameters
$query the question to ask
$default the default response ("", if none)
$topic the help topic ("", if none)
#minlen minimum code length (must be 0 or greater)
#maxlen maximum code length (must be 1 or greater)
Return value
A string which is the slash code without an initial backslash.
Remarks
The code must be made up of letters, digits, or underscores.
No other characters are allowed. The length of the code, not
counting the backslash, must be between #minlen and #maxlen
characters, inclusive.
If the default does not begin with a backslash, one is added
when it is displayed.
To make an answer obligatory, set #minlen to a value of 1 or
greater.
User error handling
The following error conditions are detected: invalid characters
in code, code too long or too short, and null response when
#minlen is greater than zero. If an error occurs, a message is
displayed and the user is required to try again.
Parameter validation
If #maxlen is greater than the constant .MAXCODE, then #maxlen
is reset to .MAXCODE. No error message is displayed in this
case.
If #minlen is greater than #maxlen, #minlen is set to 1,
#maxlen is set to 80, and an internal error message is
displayed.
No other parameter validation is done. If the $default
parameter contains invalid characters or is outside the length
limits, the error will be detected as a user error.
Example
; get a slash code from the user with a default value of
; 'w', and a length from 1 to 8 characters
$record_marker=*get_code("Record marker","w",+
"recmark",1,8)
_________________________________________________________________
*get_filespec($query,$defpath,$defname,$defext,$topic)
_________________________________________________________________
Description
Gets a well-formed filespec from the user, using default values
for any parts that the user does not supply. If the user
enters dir, or dir followed by a filespec, the directory is
displayed and the query is redisplayed.
Parameters
$query the question to ask
$defpath default drive and subdirectory path
$defname default file name (without extension)
$defext default file extension
$topic the help topic ("", if none)
Return value
A string which is a well-formed filespec containing drive, a
subdirectory path, filename, and extension.
Global variables used
$drive the drive part of the returned filespec
$subdir the subdirectory part of the returned filespec
$name the name part of the returned filespec
$ext the extension part of the returned filespec
Remarks
The parameters which specify the defaults must be formed as
follows. Any of them may also be a null string, in which case
no default will be supplied for that part of the filespec. See
.FILECHARS on page 14 for a list of the characters valid in
subdirectory names, file names, and extensions.
$defpath A drive designator including colon (A:), a
subdirectory list optionally ending with a backslash
(my\sub\dir\), or a drive and subdirectory
(C:\some\dir). If the colon is left off a drive
designator, it will be interpreted as a subdirectory
name. For example, in C\some\dir, the C refers to a
directory on the current drive, not to drive C:.
$defname A file name part containing one to eight valid
characters (my_file). It must not contain a leading
colon or backslash, or a trailing dot.
$defext A file extension containing one to three characters,
with an optional dot at the beginning. (The dot is
not optional in the filespec, but the subroutine will
add one for you if you omit it.)
The returned filespec is parsed and assigned to the global
filespec variables as follows:
$drive Contains the drive letter and colon (A:) or a null
string if the returned filespec contains no drive
specification.
$subdir Contains the subdirectory list from the filespec,
including the trailing backslash. Contains the null
string if the filespec has no subdirectory component.
$name Contains the filename part of the filespec.
$ext Contains the extension part of the filespec,
including the dot. However, if the user enters a
filespec that contains no extension or dot, and no
default is supplied, then this variable will contain
a null string.
Note that on return from *get_filespec, the values of these
four variables are such that their concatenation is guaranteed
to be a valid filespec. In fact, $drive$subdir$name$ext will
have exactly the same value as the return value of the
function.
Note, too, that *get_filespec does not check to see if the file
actually exists. Use *get_input_file to confirm the existence
of an input file.
User error handling
The user's reply must be a well-formed filespec. If it is not,
the user receives a message explaining which part (or parts) of
the filespec were not valid, and is then required to re-enter
the filespec.
Example
; get a filespec and form a name with a different
; extension (as defined in .NEW)
;
$oldfile=*get_filespec("File name","","","","")
$newfile=$drive$subdir$name.NEW
_________________________________________________________________
*get_fixed_output($filespec,#size,#allow_sub,$query,$topic)
_________________________________________________________________
Description
Get the name of a valid file for output, using a predefined
name if possible. If the named file cannot be created, inform
the user and optionally get a substitute name. The subroutine
ensures that there is enough space for the file on the output
device.
Parameters
$filespec filespec for proposed file name and location
#size size required (in kilobytes); 0, if no requirement
#allow_sub .YES if the user can supply an alternate name; .NO
otherwise
$query question to ask if the user needs to supply new
name
$topic the help topic ("", if none)
Return value
A string which is the validated filespec of the output file.
Global variables used
$drive the drive part of the returned filespec
$subdir the subdirectory part of the returned filespec
$name the name part of the returned filespec
$ext the extension part of the returned filespec
Remarks
This subroutine is used when the programmer needs a predefined
or "fixed" filename to communicate between programs. For
example, the sample program in chapter 4 dynamically generates
and runs a PTP program. The user should not be bothered with
supplying a filename for this intermediate file. On the other
hand, rather than going ahead and simply using *open with a
hard-coded filespec, a RAP program should check that the
filespec is well-formed, that there is available disk space to
create the file, and that the file does not exist already as a
read-only file. *Get_fixed_output is meant for such files.
If a file matching $filespec already exists, it is deleted
without interacting with the user.
If the #size parameter is greater than zero, *get_fixed_output
ensures that there are at least #size kilobytes of free space
on the output drive. If there is not enough space, the user is
requested to delete some files. This is done by means of an
internal call to ensure_space; see the entry for that procedure
for a description of the behavior and potential risks of this
operation. Because of these risks, you are advised to call
*get_fixed_output either before the user has entered extensive
data, or after such data has been written to a file and the
file has been closed.
If *get_fixed_output cannot succeed because the proposed file
exists already as a read-only file, the user is informed and
optionally prompted for a different filespec. Normally you can
allow the user to supply an alternate filespec. Occasionally,
however, programs do require an exact filename. For example,
user-defined characters for the JAARS ED program (JAARS 1985)
must be in a file named ED.CHR. In such cases the #allow_sub
parameter should be set to .NO. When #allow_sub is .YES,
$query is used for the interactive prompt, and $topic defines
the relevant help topic should the user to ? or help to ask for
help on that prompt.
If substitution is not allowed and the subroutine finds that an
output file of the required name cannot be opened, then the RAP
program cannot successfully proceed. Therefore, an error
message identifying the write-locked file is displayed and the
RAP program is terminated. If $topic is defined, the help text
for that topic is first displayed in order to give the user a
context-sensitive explanation of what went wrong and how it
might be fixed. Thus when #allow_sub is .NO, the help topic
functions as a context-sensitive error message, rather than a
user-requested explanation.
*Get_fixed_output does not open the file. Its purpose is to
get a filespec which may be used with *open or with an external
program using xs or xcall.
See the remarks under *get_filespec for an explanation of what
is returned in the four global filespec variables ($drive,
$subdir, $name, and $ext).
The subroutine to get a fixed input file is mount_file.
Example
; Extract selected records, then format them.
; Selected records are first written to $intermediate,
; which becomes the input file for the formatting table.
$infile=*get_input_file("Input file","","","","")
$orig_name=$name
$filespec=$drive$subdir\EXTRACT.OUT
$intermediate=*get_fixed_output($filespec,#filesize,+
.YES,"Temporary file","")
$outfile=*get_output_file("Output file",$drive$subdir,+
$orig_name,".OUT",#filesize)
xcall cc -t extract.cct -o $intermediate $infile
xcall ms -t exformat.cct -o $outfile $intermediate
xs del $intermediate
_________________________________________________________________
*get_input_file($query,$defpath,$defname,$defext,$topic)
_________________________________________________________________
Description
Gets the name of an existing file for input. Displays
directory if user enters dir, or dir followed by a filespec.
Requires user to select another file or to rename the file if
the requested input file has .TMP or .BAK extension. If the
user enters dir, or dir followed by a filespec, the directory
is displayed and the query is redisplayed.
Parameters
$query the question to ask
$defpath default drive and subdirectory path
$defname default file name (without extension)
$defext default file extension
$topic the help topic ("", if none)
Return value
A string which is the filespec of an existing input file.
Global variables used
#filesize the size of the input file in kilobytes
$drive the drive part of the returned filespec
$subdir the subdirectory part of the returned filespec
$name the name part of the returned filespec
$ext the extension part of the returned filespec
Remarks
This subroutine does not open the file. Its purpose is to get
a valid filespec of an existing file which may be used with
*open or with an external program using xs or xcall.
See the remarks under *get_filespec for the constraints on
values of the default filespec parameters ($defpath, $defname,
and $defext), and for an explanation of exactly what is
returned in the four global filespec variables ($drive,
$subdir, $name, and $ext).
The file size returned in #filesize is rounded up to the
nearest kilobyte. Note that RAP's built-in functions
*filesize, *freesp, and *memfree work in units of bytes, rather
than kilobytes. The programmer who wants to mix COMMON's high-
level routines with direct calls to RAP's built-in functions
must be sure to compensate. To convert from kilobytes to
bytes, multiply by 1024. To round up from bytes to the nearest
kilobyte, add 1023 and divide by 1024.
User error handling
The user must enter the name of an already-existing file. If
the named file does not exist, an error message is displayed
and the query is redisplayed. In addition, the input file
cannot have the extensions .BAK or .TMP. If such an extension
is entered, the user is given the choice of entering a
different filespec, or of renaming the .TMP or .BAK file to a
different extension. (This function must prohibit these two
extensions in order to guarantee that *make_tmp_output and
make_bak_file will work on the input file.)
Example
; get file names, then open files
$infile=*get_input_file("Input file","","","","")
$outfile=*get_output_file("Output file",$drive$subdir,+
$name,".OUT",#filesize)
#in = *open($infile)
#out = *open($outfile,"w")
_________________________________________________________________
*get_num($query,$default,$topic,#min,#max)
_________________________________________________________________
Description
Gets a numeric answer from the user. A default may be
supplied, and the answer is forced to be within minimum and
maximum limits.
Parameters
$query the question to ask
$default the default response ("", if none)
$topic the help topic ("", if none)
#min minimum value allowed
#max maximum value allowed
Return value
A number which is the value of the user's response, guaranteed
to be between the specified minimum and maximum values,
inclusive.
Remarks
Note that the default is a string variable, not a numeric
variable. This is so the subroutine can distinguish between a
default of "0" (that is, return 0 if the user only presses
Enter) and "no default" (that is, the user cannot just press
Enter). #Min and #max can be effectively disabled by setting
them to the smallest and largest numeric values allowed by RAP.
Instead of using literal numbers in your program for this
purpose, use the symbolic values .MININT and .MAXINT. Using
the symbolic values means your program will not have to be
revised if a future version of RAP allows larger numeric
variables.
User error handling
The following error conditions are detected: input not a
number, input out of range (that is, not between #min and
#max), and null response when no default is supplied. In each
case an error message is displayed, and the query is
redisplayed.
Parameter validation
If #min is greater than #max, #min and #max are set to the
smallest and largest values RAP allows, and an internal error
message is displayed.
If a default is supplied that is not a valid number, an
internal error message is displayed and $default is changed to
a null string (that is, no default).
Example
; get page length, with a default of 66,
; minimum of 20, and maximum of 132
#page_length=*get_num("Page length","66",$topic,20,132)
_________________________________________________________________
*get_output_file($query,$defpath,$defname,$defext,$topic,#size)
_________________________________________________________________
Description
Get the name of a valid file for output. If the named file
already exists, the user must confirm that it should be
overwritten. The subroutine also ensures that there is enough
space for the file on the output device. If the user enters
dir, or dir followed by a filespec, the directory is displayed
and the query is redisplayed.
Parameters
$query the question to ask
$defpath default drive and subdirectory path
$defname default file name (without extension)
$defext default file extension
$topic the help topic ("", if none)
#size size required (in kilobytes); 0, if no requirement
Return value
A string which is the validated filespec of the output file.
Global variables used
$drive the drive part of the returned filespec
$subdir the subdirectory part of the returned filespec
$name the name part of the returned filespec
$ext the extension part of the returned filespec
Remarks
This subroutine does not open the file. Its purpose is to get
a filespec which may be used with *open or with an external
program executed by means of xs or xcall.
See the remarks under *get_filespec for the constraints on
values of the default filespec parameters ($defpath, $defname,
and $defext), and for an explanation of exactly what is
returned in the four global filespec variables ($drive,
$subdir, $name, and $ext).
If the #size parameter is greater than zero, the subroutine
ensures that there are at least #size kilobytes of free space
on the output drive. If there is not enough space, the user is
requested to delete some files. This is done by means of an
internal call to ensure_space; see the entry for that procedure
for a description of the behavior and potential risks of this
operation. Because of these risks, you are advised to call
*get_output_file either before the user has entered extensive
data, or after such data has been written to a file and the
file has been closed.
Example
; Get file names and run the 'extract' change table.
; Suggested output file name is input file name with
; .OUT extension.
$infile=*get_input_file("Input file","","","","")
$outfile=*get_output_file("Output file",$drive$subdir,+
$name,".OUT",#filesize)
xcall cc -t extract.cct -o $outfile $infile
_________________________________________________________________
*get_str($query,$default,$topic,#minlen,#maxlen)
_________________________________________________________________
Description
Gets a string from the user. A default answer may be returned
if the user just hits Enter, or the user may be required to
give an explicit answer. The length of the answer must be
between minimum and maximum limits.
Parameters
$query the question to ask
$default the default response ("", if none)
$topic the help topic ("", if none)
#minlen minimum string length (must be 0 or greater)
#maxlen maximum string length (must be 1 or greater)
Return value
A string which is the user's answer. If a $default parameter
is supplied, that string is returned if the user simply hits
Enter.
Remarks
To make a non-null answer obligatory, set #minlen to a value of
1 or more. Note that the user may still hit just Enter to
select the default, as long as the length of $default is equal
to or greater than #minlen.
To allow the function to return a null string, you must both
specify $default as a null string ("") and specify #minlen as
0. It is then possible for the user to give a null answer by
pressing Enter.
To require the user to type an explicit answer, specify
$default as a null string, but specify #minlen as 1 or greater,
thus disabling the null default.
User error handling
If the answer is too short or too long, a message is displayed
and the user must try again.
Parameter validation
If #minlen is greater than #maxlen, #minlen is set to 1,
#maxlen is set to 80, and an internal error message is
displayed.
If a default is supplied, but #minlen is greater than 0, the
user will be unable to select the default by pressing Enter.
No test is made for this error.
Example
; get user's name: a response is obligatory
; and limited to 60 characters
$name=*get_str("What is your name","","",1,60)
_________________________________________________________________
kbflush()
_________________________________________________________________
Description
Flushes the type-ahead buffer.
Parameters
None.
Return value
None.
Remarks
Kbflush is used to ensure that subsequent keyboard input comes
after a certain point in the program, not from type-ahead
input. As the example below illustrates, there are instances
in which input that has been typed ahead (whether purposely or
inadvertently) could have disastrous results. Executing
kbflush right before a query allows the programmer to be sure
that the response is the user's answer to that question, and
not an accidental type ahead.
Example
kbflush()
if (*yes("Do you want to delete all files on drive +
A:","",""))
xs del a:*.*
end if
Here is an even safer version of the same thing, especially for
systems with slow display speed:
t:Do you want to delete all files on drive A:\
kbflush()
if (*yes("","",""))
xs del a:*.*
end if
_________________________________________________________________
make_bak_file($permname,$tmpname)
_________________________________________________________________
Description
Updates a temporary file. The existing .BAK file, if any, is
deleted; the existing copy of $permname is renamed as a .BAK
file; and the temporary file $tmpname is renamed as $permname.
Parameters
$permname the name of the permanent copy of the file
$tmpname the name of the temporary file
Return value
None.
Remarks
This subroutine assumes that the file in $permname does not
have the extension .BAK, and that the file in $tmpname has the
extension .TMP. These conditions can be ensured by using
*get_input_file to get $permname and *make_tmp_output to get
$tmpname.
User error handling
An existing .BAK file must be deleted by this subroutine. If
the existing .BAK file is read-only, an error message is
displayed and the update is not performed.
Example
; get file to be reformatted
$infile=*get_input_file("Input file","","",+
".TXT","reformat")
; get temporary output file
$tmpfile=*make_tmp_output($infile,#filesize)
; do the reformatting
xs cc -t reformat.cct -o $tmpfile $infile
; give the reformatted file the original name
make_bak_file($infile,$tmpfile)
_________________________________________________________________
make_bak_to_bat($permname,$tmpname,#bat)
_________________________________________________________________
Description
Creates batch file lines to perform a temporary file update.
The existing .BAK file, if any, is deleted; the existing copy
of $permname is renamed as a .BAK file; and the temporary file
$tmpname is renamed as $permname.
Parameters
$permname the name of the permanent copy of the file
$tmpname the name of the temporary file
#bat the file descriptor for the batch file to write
Return value
None.
Remarks
This subroutine assumes that the file in $permname does not
have the extension .BAK, and that the file in $tmpname has the
extension .TMP. These conditions can be ensured by using
*get_input_file to get $permname and *make_tmp_output to get
$tmpname.
Parameter validation
Because the update of file names is done by a batch file, RAP
cannot provide any error messages, nor can it easily find out
if the update failed. If an existing .BAK file is read-only,
COMMAND.COM will generate the following sequence of error
messages on the screen, but they may not remain on the screen
long enough for the user to notice them.
File not found (or Access denied)
Duplicate file name or File not found
Duplicate file name or File not found
Example
; RAP is run from a batch file called GO.BAT
; containing:
; RAP MY_PROG
; DOIT
; The RAP program writes DOIT.BAT, then GO.BAT
; automatically chains to it when RAP exits
#bat = *open("doit.bat","w")
; get input file and temporary output
$infile=*get_input_file("Input file","","",+
".TXT","reformat")
$tmpfile=*make_tmp_output($infile,#filesize)
; write command line to do the reformatting
wr #bat, xs cc -t reformat.cct -o $tmpfile $infile
; generate batch file commands to create the backup file
make_bak_to_bat($infile,$tmpfile,#bat)
closef #bat
bye ; and execute the batch
; file we just created.
_________________________________________________________________
*make_tmp_output($filespec,#size)
_________________________________________________________________
Description
Creates a .TMP file name based on the file name given as an
input parameter, and ensures that there is sufficient space for
the .TMP file to be written.
Parameters
$filespec the filespec for the base file
#size size required (in kilobytes); 0, if no requirement
Return value
A string which is the filespec of the .TMP file which is valid
for output.
Remarks
This subroutine does not open the file. Its purpose is to
produce a filespec which may be used with *open or with an
external program executed by means of xs or xcall.
This subroutine assumes that $filespec is a valid input file,
and that it does not have the extension .TMP. These can be
ensured by always calling *get_input_file first, and using the
filespec it returns as the filespec for *make_tmp_output.
If there is already another file with the resulting .TMP name,
it is deleted without asking the user. If such a file is read-
only (and thus cannot be deleted) an error message is
displayed.
If the #size parameter is greater than zero, *make_tmp_output
ensures that there are at least #size kilobytes of free space
on the output drive. If there is not enough space, the user is
requested to delete some files. This is done by means of an
internal call to ensure_space; see the entry for that procedure
for a description of the behavior and potential risks of this
operation. Because of these risks, you are advised to call
*make_tmp_output either before the user has entered extensive
data, or after such data has been written to a file and the
file has been closed.
If the #size parameter is greater than zero, the subroutine
ensures that there is at least #size kilobytes of free space on
the output device. If there is not enough space, the user is
required to delete some files from the device. This is a
potentially risky proposition: the user may not have any
unnecessary files on that disk! Nor does the program know if
it is safe to change disks at that point. If the user cannot
make enough room, his only recourse is to abort the RAP program
by typing Ctrl-C, which will lose any data that has not been
written to a file. The behavior of this subroutine is likely
to be revised in future versions. In the meantime, you are
advised to call *make_tmp_output either before the user has
entered extensive data, or after such data has been written to
a file and the file has been closed.
Example
;the CC table will probably double the size
; of the input file
$infile=*get_input_file("Input file","","","","")
$tmpfile=*make_tmp_output($infile, #filesize * 2)
xcall cc -t process.cct -o $tmpfile $infile
_________________________________________________________________
message($text)
_________________________________________________________________
Description
Rings the bell, displays a message, flushes the type-ahead
buffer, and waits until the user presses Enter.
Parameters
$text the message to display
Return value
None.
Remarks
The keyboard buffer is flushed to ensure that the foot
statement, used internally to pause the screen, is terminated
by the user responding to the message, rather than by any type
ahead.
To indent the message, include leading spaces in $text.
Example
message("Be sure the printer is turned on and the paper +
is lined up.")
_________________________________________________________________
mount_file($filespec,$topic)
_________________________________________________________________
Description
Ensures that the specified file is mounted and available for
use. Prompts user to change disks, if necessary and if safe to
do so.
Parameters
$filespec filespec for name and location of file
$topic the help topic ("", if none)
Return value
None.
Global variables used
#filesize the size of the file in kilobytes
$drive the drive part of the filespec
$subdir the subdirectory part of the filespec
$name the name part of the filespec
$ext the extension part of the filespec
Remarks
This subroutine is used when the program must read a file with
a predefined, fixed name. Rather than going ahead to simply
use *open with a hard-coded filespec, a RAP program should
ensure that the file is available for input. Mount_file is
meant for this purpose. If this procedure succeeds, $filespec
can then be safely used with *open or as a parameter to an
external program using xs or xcall.
If the file named in $filespec cannot be found, then an error
message identifying the missing file and its expected location
is displayed. If $topic is defined, the help text for that
topic is also displayed in order to give the user a context-
sensitive explanation of what went wrong. If no files are open
and it is thus safe to change disks (see discussion under
mount_volume), the procedure invites the user to mount a
different disk volume. Otherwise, the RAP program cannot
proceed and is terminated. For this reason, it is best to call
this procedure when no other files are open and before the user
is required to interact with the RAP program to enter
information.
Unlike RAP's built-in *existf function, which uses the $path
variable to search a number of directories when the filespec
specifies no drive or subdirectory path, mount_file requires
that the file be in the current directory if $filespec gives no
location. For this reason, mount_file should be used to verify
the existence of fixed-name files for use as parameters to
external commands via xs or xcall. Using *existf in such cases
may give the wrong answer, since the DOS command processor will
not search the subdirectories in its PATH variable to look for
data files.
Besides ensuring availability, this subroutine has the side
effect of returning the file size and parsing the filespec into
its four main components. In this respect, mount_file is like
the functions for input and output files and fills the spot of
a get_fixed_input function. See the remarks under
*get_filespec for an explanation of what is returned in the
four global filespec variables ($drive, $subdir, $name, and
$ext).
The file size returned in #filesize is rounded up to the
nearest kilobyte. Note that RAP's built-in functions
*filesize, *freesp, and *memfree work in units of bytes, rather
than kilobytes. The programmer who wants to mix COMMON's high-
level routines with direct calls to RAP's built-in functions
must be sure to compensate. To convert from kilobytes to
bytes, multiply by 1024. To round up from bytes to the nearest
kilobyte, add 1023 and divide by 1024.
Example
; Read the user's config.sys to see if the system is
; configured adequately for our application
mount_file("\\config.sys","")
#config=*open("\\config.sys")
...
_________________________________________________________________
mount_program($filespec,$topic)
_________________________________________________________________
Description
Ensures that the specified program file is mounted and
available for use. Prompts user to change disks, if necessary
and if safe to do so.
Parameters
$filespec filespec for name and location of file
$topic the help topic ("", if none)
Return value
None.
Remarks
This subroutine is used when the RAP program must run an
external program. Rather than going ahead and calling it with
xs or xcall, a RAP program should ensure that the external
program is available for use. Mount_program is meant for this
purpose. If this procedure succeeds, $filespec can then be
safely used as an external program name in xs or xcall.
If the program named in $filespec cannot be found, then an
error message identifying the missing file and its expected
location is displayed. If $topic is defined, the help text for
that topic is also displayed in order to give the user a
context-sensitive explanation of what went wrong. If no files
are open and it is thus safe to change disks (see discussion
under mount_volume), the procedure invites the user to mount a
different disk volume. Otherwise, the RAP program cannot
proceed and is terminated. For this reason, it is best to call
this procedure when no other files are open and before the user
is required to interact with the RAP program to enter
information.
This procedure uses the $path variable to search a number of
directories when $filespec specifies no drive or subdirectory.
RAP initializes $path to the value of DOS's PATH variable.
Thus, as long as the RAP program does not alter the value of
$path, any program name validated by mount_program will be
successfully located by the DOS command processor when the
external command is executed.
Example
; Ensure that CC and PTPC are installed on the user's
; system before beginning to ask all the questions
mount_program("CC.EXE","")
mount_program("PTPC.EXE","")
_________________________________________________________________
mount_volume($drive,$id,$name)
_________________________________________________________________
Description
Ensures that the disk volume mounted in a particular drive is
the one needed. Prompts user to change disks, if necessary and
if safe to do so.
Parameters
$drive the drive to use
$id the volume ID of the desired disk
$name name of the desired disk (for display purposes)
Return value
None.
Remarks
If the volume mounted in $drive does not have the given $id,
then the user is asked to mount the volume. The prompt given
is "Place the $name disk in drive $drive", in which the values
of the $name and $drive parameters are substituted. While that
name could be identical to the volume ID on the disk, it need
not be. For instance, $name can exceed the eleven character
length limit of a volume ID in order to refer to the disk in a
more natural way.
Because current versions of MS-DOS are not always aware of
disks being changed, it is not safe to change a disk if there
are files open on it. In the case of an input file, the
program might go ahead and read garbage from the new disk. In
the case of an output file, it is likely to destroy the File
Allocation Table on the new disk when the file is closed.
Unfortunately, a RAP program cannot tell which drives any open
files are on. Nor is it possible to tell whether they are open
for input or for output. The best we can do is to know if
there are any files open at all. Therefore, to ensure complete
safety, mount_volume requires that there are no open files. If
there are, an internal error message is displayed and the
program terminates. Programmers must therefore ensure that no
files are open whenever mount_volume is called. (The help file
is an exception; COMMON automatically takes care of that.) In
cases where there is a legitimate need to keep files on one
disk open while another disk is replaced, the programmer must
define a new procedure (and assume the risks
involved!)≡mount_volume will not allow a new disk to be mounted
in that situation.
Example
; ensure that the IT program disk is in drive B:
mount_volume("B:","IT_PROGS","IT Programs Disk")
_________________________________________________________________
*no($query,$default,$topic)
_________________________________________________________________
Description
Tests if the user answers no to the query, supplying an
optional default response.
Parameters
$query the question to ask
$default the default response ("", if none)
$topic the help topic ("", if none)
Return value
A number which is .YES if the answer was no, or .NO if it was
yes.
Remarks
The user's response must be one of the following: y, yes, n, or
no. Case is ignored, as are leading or trailing blanks.
User error handling
If an invalid response is given, *no displays the message
"Please type yes or no" and redisplays the query.
Parameter validation
*No does not validate $default before using it. This means
that if an invalid $default was passed, it will be displayed,
but the user error handling will reject it if the user presses
just Enter.
Example
loop
...
repeat if (*no("Is everything correct","",""))
...
end loop
_________________________________________________________________
open_help($helpfile)
_________________________________________________________________
Description
Opens the programmer-supplied help file for the RAP program.
Parameters
$helpfile the name of the help file
Return value
None.
Remarks
The help file name may be a simple filename or a full filespec
(including drive and subdirectory). If a simple filename is
given, open_help searches for it on the default directory,
followed by all directories listed in DOS's PATH variable. If
the filespec includes a drive or subdirectory, open_help tries
to find the named file only and does not look in other
locations.
If the help file cannot be found, the user is given the choice
of entering a new filespec for the help file, continuing
without help available, or exiting the program.
See chapter 3 for a full discussion of the help system provided
by the COMMON subroutine library.
Example
proc main
open_help("demo.hlp")
explain("intro_to_demo")
...
end proc
_________________________________________________________________
*parse_filespec($filespec,#report)
_________________________________________________________________
Description
Validates the well-formedness of a filespec, and parses the
four components of the filespec into the four global variables
$drive, $subdir, $name, and $ext. The programmer may
optionally suppress the reporting of error messages.
Parameters
$filespec the filespec to validate and parse
#report .YES, if filespec errors should be reported to the
screen; .NO, otherwise
Return value
A number which is .YES if the filespec is well-formed, or .NO
if it is not.
Global variables used
$drive the drive part of the returned filespec
$subdir the subdirectory part of the returned filespec
$name the name part of the returned filespec
$ext the extension part of the returned filespec
Remarks
If the return value is .NO, the values in the global variables
are undefined.
This procedure makes no attempt to open the file named in
$filespec; nor does it test that the file exists. It merely
tests if the filespec is syntactically well-formed.
A valid filespec is parsed and assigned to the four global
filespec variables as follows:
$drive Contains the drive letter and colon (A:) or a null
string if the returned filespec contains no drive
specification.
$subdir Contains the subdirectory list from the filespec,
including the trailing backslash. Contains the null
string if the filespec has no subdirectory component.
$name Contains the filename part of the filespec.
$ext Contains the extension part of the filespec,
including the dot. However, if the user enters a
filespec that contains no extension or dot, and no
default is supplied, then this variable will contain
a null string.
Note that on return from *parse_filespec, the values of these
four variables are such that their concatenation is guaranteed
to be a valid filespec. In fact, $drive$subdir$name$ext will
have exactly the same value as the input parameter $filespec.
Parameter validation
*Parse_filespec ensures that $filespec is syntactically well-
formed. It ensures the following: that the drive designator,
if any, is valid (see the entry for *val_drive); that only
valid characters occur in the subdirectory names, file name,
and extension (see .FILECHARS on page 14); and that these
components do not exceed the maximum allowed lengths of 8
characters for subdirectory and file names and 3 characters for
the extension.
When $filespec is not well-formed, *parse_filespec is able to
display a message describing exactly what is wrong with the
filespec. The #report parameter allows the programmer to
control whether or not these messages are displayed. In an
interactive routine, this parameter would normally be set to
.YES in order to give the user as much information as possible
about why the filespec just typed was invalid. However, in a
noninteractive routine, such as when a program-supplied
filespec is being parsed, such messages would be mysterious to
the user. In such cases, #report should be set to .NO, and the
program should be written to test the return value and make
some sensible response if the parse fails.
Example
; Is the name part of $filespec exactly 6 characters
; long?
num function *six_char_name($filespec)
; use local copies of filespec variables so as not to
; interfere with global ones
declare $drive,$subdir,$name,$ext
if (*parse_filespec($filespec,.NO) +
and *strlen($name) == 6)
return .YES
else
return .NO
end if
end function
_________________________________________________________________
retry($message,$topic)
_________________________________________________________________
Description
Rings the bell and displays an error message. It then adds
"Try again (type ? for help)" if a help topic is available, or
simply "Try again" if no help is available.
Parameters
$message the error message to display
$topic the help topic for the question that was answered
incorrectly
Return value
None.
Remarks
Because *retry adds "Try again" to the end of the message, it
is suitable only for error messages regarding incorrect user
response to a question. For more general error messages, use
*message.
If the total length of $message plus the "Try again" tag
exceeds the width of the screen, the "Try again" is displayed
on a new line. No check is made, however, to see if $message
will fit on one screen line.
To indent the message, include leading spaces in $message. The
"Try again" tag will be indented the same number of spaces if
it is displayed on a second line.
Example
; get unique input and output markers
loop
$in_marker=*get_code("Input record marker","","",+
0,.MAXCODE)
$out_marker=*get_code("Output record marker","","",+
0,.MAXCODE)
exit if ($in_marker <> $out_marker)
retry("Record markers must be different","")
end loop
_________________________________________________________________
*to_lower($string)
_________________________________________________________________
Description
Converts all upper-case letters in $string to lower case.
Parameters
$string the string to convert
Return value
A string which is a copy of $string that has all upper-case
letters converted to lower case. Other characters in $string
are unchanged.
Example
; ensure standard format marker is all lower case
$marker=*to_lower($marker)
_________________________________________________________________
*to_upper($string)
_________________________________________________________________
Description
Converts all lower-case letters in $string to upper case.
Parameters
$string the string to convert
Return value
A string which is a copy of $string that has all lower-case
letters converted to upper case. Other characters in $string
are unchanged.
Example
; ensure drive name is upper case
$drive=*to_upper($drive)
_________________________________________________________________
*trim($string)
_________________________________________________________________
Description
Removes leading and trailing blanks (that is, spaces and tabs)
from a string.
Parameters
$string the string to trim
Return value
A string which is a copy of $string without any leading or
trailing blanks.
Remarks
A string consisting entirely of blanks is converted to a null
string.
Example
$address=*get_str("Address","","address",0,60)
$address=*trim($address)
_________________________________________________________________
*val_dir($dir)
_________________________________________________________________
Description
Validates a directory path as being syntactically well-formed.
Parameters
$dir partial path (includes only subdirectory names)
Return value
A number which is .YES if the path is well-formed, or .NO if it
is invalid.
Remarks
Note that this subroutine does not check to see if the path
actually exists. It only checks the syntax of the path
expression.
Displays an error message if the path contains invalid
characters. The path does not have to begin or end with a
backslash.
Valid characters for a path include the backslash and all
characters which are valid in a subdirectory name. These are
the same as the characters valid in a file name (see .FILECHARS
on page 14 for a list).
Example
loop
$directory=*get_str("Directory for .TMP files","",+
"tmp_files",0,65)
exit if (*val_dir($directory))
end loop
_________________________________________________________________
*val_drive($drive)
_________________________________________________________________
Description
Validates a drive designator as referring to an existing drive.
Parameters
$drive the drive designator to be tested
Return value
A number which is .YES if the drive exists, or .NO if it does
not.
Remarks
$Drive may be a single letter, or it may be a letter followed
by a colon. $Drive may also contain the null string, in which
case it is a valid designation for the current.
On PC-compatibles, this subroutine works as expected, returning
.YES for valid drives, and .NO for invalid drives.
On the Sharp PC-5000, *val_drive is complicated by a quirk of
that machine: the operating system thinks that drives A:
through O: are always available. Attempting to access one of
the nonexistent drives (like E: or M:) invokes the MS-DOS
critical error handler. The user will get the "Abort, Retry,
Ignore" message, and will have to abort, losing any data that
was not yet written to a file. *Val_drive attempts to get
around this problem in two ways:
The first method requires no user intervention. All drive
requests are checked against the list "ABCDG" and are
considered invalid if they are not on the list. ("P" for a
ramdisk is automatically added to the list if a ramdisk is
installed.) This method is not perfect, since it recognizes
all possible drives for the Sharp, not just the ones actually
installed.
The second method requires the RAP program to be invoked with
the command-line parameter /drive=, where the = is followed by
a list of actual drive letters. This is, unfortunately,
specific to the particular machine. For example, if the user
has a dual 5 1/4" drive, and uses a ramdisk, the command-line
parameter should be:
rap /drive=ABCDP
Regardless of machine type, the list of valid drive letters is
contained in the global variable $valdr. Your programs may
test the value of this variable, but should never change it.
User error handling
An error message is displayed if the drive is invalid.
Example
; get and validate a drive designator
loop
$dr=*get_str("What drive will you be using","","",2,2)
exit if (*val_drive($dr))
end loop
_________________________________________________________________
*val_ext($ext)
_________________________________________________________________
Description
Validates a file name extension as being syntactically well
formed.
Parameters
$ext the extension to be checked
Return value
A number which is .YES if the extension is valid, or .NO if it
is not.
Remarks
Displays an error message if extension is invalid. An invalid
extension is one that is more than three characters long,
contains characters not allowed in filenames, contains a
backslash or colon, or has a dot that is not the first
character. Note that the null string is a valid extension.
Valid characters for extensions are the same as those for file
names. See .FILECHARS on page 14 for a list.
Example
loop
$newext=*get_str("New extension for $name$ext","","",+
0,4)
$newext=*ensure_dot($newext)
exit if (*val_ext($newext))
end loop
$filespec=$name$newext
_________________________________________________________________
*yes($query,$default,$topic)
_________________________________________________________________
Description
Tests if the user answers yes to the query, supplying an
optional default response.
Parameters
$query the question to ask
$default the default response ("", if none)
$topic the help topic ("", if none)
Return value
A number which is .YES if the answer was yes, or .NO if it was
no.
Remarks
The user's response must be one of the following: y, yes, n, or
no. Case is ignored, as are leading or trailing blanks.
User error handling
If an invalid response is given, *yes displays the message
"Please type yes or no" and redisplays the query.
Parameter validation
*Yes does not validate $default before using it. This means
that if an invalid $default was passed, it will be displayed,
but the user error handling will reject it if the user presses
just Enter.
Example
#verbose=*yes("Do you want instructions","n",+
"instructions")